// *** LICENSE HEADER ***
// Filename: ./connector.h
// This file is part of Nodewarz 0.1
// Nodewarz is a 3d OpenGL strategy game
// Copyright (C) 2007 CZestmyr
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// *** END LICENSE HEADER ***
#ifndef NODEWARS_CONNECTOR_H
#define NODEWARS_CONNECTOR_H

#include "serec.h"
#include "definitions.h"
#include "helperfunctions.h"
#include "logger.h"
#include "messageviewer.h"
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <SDL.h>
#include <SDL_net.h>

class engine;
class player;

//Class that manages connections between clients and server
class connector{
    public:
        connector(engine* par);
        ~connector();

        //Initialization
        bool Init(Uint16 port);
        //Deinitialization
        void Deinit();
        //Tell whether the connector has been init
        bool IsInit();
        //Tell whether the connector is in server mode
        bool IsServer();

        //The client sends heartbeats, the server controls them
        //The client and server also receive other messages here and server relays them to other clients
        void Update(Sint32 dt);

        //Set server mode on or off
        void SetServer(bool newIsServer);
        //Set function that should be called if an event packet arrives
        void SetEventCallback(void (&newCallback)(engine*, const char*));

        //Server-only: Close so that noone can enter the game
        void Close();
        //Server-only: Open to be able to accept new connections
        void Open();

        //if clientNum == -1 => clent disconnecting, else server kicks the corresponding client out
        void Disconnect(int clientNum = -1);
        //Client-only: connect to a server
        bool Connect(IPaddress newServer);
        //Client only function. Return values:
        //0 - is not connected (or server response was negative)
        //1 - is connected
        //-1 - is not YET connected (waiting for server response)
        int IsConnected();

        //Both client and server send a message via this function. Server can supply client number, where the message won't be sent
        void SendMessage(const char* message, int dontSendHere = -1);

        //Prepare a net event to be sent
        void PrepareEvent(int eventtype);
        //Append integer event data
        void AppendEventDataI(int integer);
        //Append float event data
        void AppendEventDataF(float floatingpoint);
        //Must be the last AppendEventData method, called for this event before being sent
        void AppendEventDataS(const char* str);
        //Send the event to all but one client
        //If server relays some event, it sets the dontSendHere to the client he originally received the event from
        void SendEvent(int dontSendHere = -1);
        //Send the event to a single client
        void SendEventTo(int sendHere);

        //Set the client (server) name
        void SetLocalName(const char* newName);
        //Return local name buffer pointer
        const char* GetLocalName();
        //Server-only: Get a name of an other client
        const char* GetClientName(int clientnum);

        //The server sends a client list string to all the clients (for their information)
        void SendClientList();
        //The server sends a client name list string
        void SendClientNameList();

        //Sets next connected client number for the player and returns it (-1 = local)
        int SetNextClientNumber(player* pl);
        //Update the player's client number (give the player to someone else if the client disconnects)
        void UpdateClientNumber(player* pl);
    private:
        //Client-only: Send a heartbeat to server
        void SendHeartbeat();
        //Server-only: Tell whether the server is full
        bool IsFull();
        //Server-only: Get the first free client slot number
        int GetFirstFreeSlotIndex();

        //Sends the whole messageBuffer (without changes) to all (but dontSendHere) clients
        void Relay(int dontSendHere);

        //Pointer to the parent
        engine* parent;

        //A few flags
        bool isServer;
        bool isInit;
        bool isClosed;

        //Sender-receiver. This actually sends the messages over UDP
        serec sr;

        //Buffer for the incoming messages
        char messageBuffer[_SEREC_MAX_MESSAGE_LENGTH];

        //Buffer for the outgoing packets
        char outgoingMessageBuffer[_SEREC_MAX_MESSAGE_LENGTH];
        int messageBufferPointer;

        //Buffer for the local name
        char localName[33];

        //Client only data
        bool clientConnected;
        bool awaitingServerResponse;
        IPaddress server;
        Sint32 lastHeartbeat;

        //Server data
        IPaddress players[4];
        bool connected[4];
        Sint32 timeSinceLastHeartbeat[4];
        char clientNames[4][33];

        //Network event packet handler function
        void (*eventHandlerCallback)(engine*, const char*);
};

#include "engine.h"
#include "player.h"

#endif
